﻿using System.Collections.Generic;

namespace GxFramework
{
    public delegate void EventListener(IEventDispatcher target, int type, int value, string name, object body);
    public interface IEventDispatcher
    {
        bool allowMultiListener{get;}
        bool allowDuplicateListener{get;}
        bool AddEvent(int type, EventListener del);
        void RemoveEvent(int type, EventListener del);
        void SendEvent(int type, int value, string name, object body);
    }
    public class EventDispatcher : IEventDispatcher
    {
        IEventDispatcher _target;
        bool _allowMultiListener;
        bool _allowDuplicateListener;
        Dictionary<int, List<EventListener>> _eventToCallbacksMap = new Dictionary<int, List<EventListener>>();
        public EventDispatcher(bool allowMultiLister=true, bool allowDuplicateListener=false,IEventDispatcher target=null)
        {
            _target = target ?? this;
            _allowMultiListener = allowMultiLister;
            _allowDuplicateListener = allowDuplicateListener;
        }
        public bool allowMultiListener { get { return _allowMultiListener; } }
        public bool allowDuplicateListener { get { return _allowDuplicateListener; } }
        public bool AddEvent(int eventID, EventListener del)
        {
            List<EventListener> dels;
            if (!_eventToCallbacksMap.TryGetValue(eventID, out dels))
            {
                dels = ListPool<EventListener>.Get(1);
                _eventToCallbacksMap[eventID] = dels;
                dels.Add(del);
                return true;
            }
            if (!allowMultiListener)
                return false;
            if (allowDuplicateListener || !dels.Contains(del))
            {
                dels.Add(del);
                return true;
            }
            return false;
        }

        public void RemoveEvent(int eventID, EventListener del)
        {
            List<EventListener> dels;
            if (!_eventToCallbacksMap.TryGetValue(eventID, out dels))
                return;
            int len = dels.Count;
            for (int i = 0; i < len; ++i)
            {
                if (del == dels[i])
                {
                    dels.RemoveAt(i);
                    if (dels.Count == 0)
                    {
                        _eventToCallbacksMap.Remove(eventID);
                        ListPool<EventListener>.Release(dels);
                    }
                    break;
                }
            }
        }

        public void SendEvent(int type, int value=0, string name=null, object body=null)
        {
            List<EventListener> listeners;
            if (!_eventToCallbacksMap.TryGetValue(type, out listeners))
                return;

            int len = listeners.Count;

            var dels = ListPool<EventListener>.Get(len);
            dels.AddRange(listeners);

            int index;
            for (index = 0; index < len; ++index)
            {
                var del = dels[index];
                del(_target,type,value,name,body);
            }

            ListPool<EventListener>.Release(dels);
        }
    }//end class
}